package com.to8to.kitt.utils;

import java.net.NetworkInterface;
import java.util.Enumeration;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.thrift.TServiceClient;

import com.google.common.base.Objects;

public class UniqueIdGenerator {
	
	private static AtomicInteger _nextInc = new AtomicInteger( (new Random()).nextInt() );
	
	private static final int _genmachine;
	
	static {

        try {
            // build a 2-byte machine piece based on NICs info
            int machinePiece;
            {
                try {
                    StringBuilder sb = new StringBuilder();
                    Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
                    while ( e.hasMoreElements() ){
                        NetworkInterface ni = e.nextElement();
                        sb.append( ni.toString() );
                    }
                    machinePiece = sb.toString().hashCode() << 16;
                } catch (Exception e) {
                    machinePiece = (new Random().nextInt()) << 16;
                }
            }

            // add a 2 byte process piece. It must represent not only the JVM but the class loader.
            // Since static var belong to class loader there could be collisions otherwise
            final int processPiece;
            {
                int processId = new java.util.Random().nextInt();
                try {
                    processId = java.lang.management.ManagementFactory.getRuntimeMXBean().getName().hashCode();
                }
                catch ( Exception t ){
                }

                ClassLoader loader = TServiceClient.class.getClassLoader();
                int loaderId = loader != null ? System.identityHashCode(loader) : 0;

                StringBuilder sb = new StringBuilder();
                sb.append(Integer.toHexString(processId));
                sb.append(Integer.toHexString(loaderId));
                processPiece = sb.toString().hashCode() & 0xFFFF;
            }

            _genmachine = machinePiece | processPiece;
        }
        catch ( Exception e ){
            throw new RuntimeException( e );
        }
    }
	
	public static int uniqueInt()
	{
		return _nextInc.getAndIncrement(); //  +  _genmachine;
	}
	
	public static int uniqueInt(Object ... key)
	{
//		return key.hashCode();
		return uniqueInt(); // +  Objects.hashCode(key) ;
	}
	
	
	public static void main(String[] args)
	{
		Map<Integer, Integer > map = new ConcurrentHashMap<Integer, Integer >();
		
		ExecutorService threadPool = Executors.newCachedThreadPool();
        
        for (int i = 0; i < 100; i++)
        {
            threadPool.submit(new Runnable(){
                public void run()
                {
                    for(int j = 0 ; j < 100000; ++ j)
                    {
                    	int num = uniqueInt();
                    	map.put(num, 1);
                    }
                }
            });
        }
        threadPool.shutdown();
        try
        {
            while (!threadPool.awaitTermination(10000, TimeUnit.MILLISECONDS))
            {
                Thread.sleep(10000);
            }
        }
        catch (InterruptedException e)
        {
        	
        }
		
        System.out.println(map.size());
		
	}
	
}
